package com.mobimagic.lockscreen.remaintime;

import java.util.ArrayList;
import java.util.List;

import com.mobimagic.lockscreen.remaintime.aidl.ChargingData;
import com.mobimagic.lockscreen.remaintime.aidl.ChargingDatas;

public abstract class CalcSlopeStrategy {

    public abstract double getSuggestSlope(int index, ChargingDatas chargingData);

    public double getSlope(int index, ChargingDatas chargingData) {
        List<ChargingData> chargingDatas = chargingData.chargingDatas;
        int size = chargingDatas.size();
        if (index < 1 || size <= 1) {
            return -1;
        }
        ChargingData pre = chargingDatas.get(index - 1);
        ChargingData current = chargingDatas.get(index);
        int deltaTime = current.getTime() - pre.getTime();
        int deltaBattery = current.getBattery() - pre.getBattery();
        float slope = deltaBattery * 1f / deltaTime;
        return slope;
    }

    public static int getSlopeStrategyIndex(Class<? extends CalcSlopeStrategy> clazz) {
        if (clazz == CalcSlopeStrategy.Simple.class) {
            return 0;
        } else if (clazz == CalcSlopeStrategy.DoubleSimple.class) {
            return 1;
        } else if (clazz == CalcSlopeStrategy.Average.class) {
            return 2;
        } else if (clazz == CalcSlopeStrategy.Exponential.class) {
            return 3;
        }
        return 0;

    }

    public static CalcSlopeStrategy getInstance(int i) {
        CalcSlopeStrategy calcSlopeStrategy;
        switch (i) {
        case 0:
            calcSlopeStrategy = new CalcSlopeStrategy.Simple();
            break;
        case 1:
            calcSlopeStrategy = new CalcSlopeStrategy.DoubleSimple();
            break;
        case 2:
            calcSlopeStrategy = new CalcSlopeStrategy.Average();
            break;
        case 3:
            calcSlopeStrategy = new CalcSlopeStrategy.Exponential();
            break;

        default:
            calcSlopeStrategy = new CalcSlopeStrategy.Simple();
            break;
        }
        return calcSlopeStrategy;
    };

    public static class Simple extends CalcSlopeStrategy {

        @Override
        public double getSuggestSlope(int index, ChargingDatas chargingData) {
            List<ChargingData> chargingDatas = chargingData.getChargingDatas();
            ChargingData pre = chargingDatas.get(index - 1);
            ChargingData current = chargingDatas.get(index);
            int deltaTime = current.getTime() - pre.getTime();
            int deltaBattery = current.getBattery() - pre.getBattery();
            float battery_time = deltaBattery * 1f / deltaTime;
            return battery_time;

        }

    }

    public static class DoubleSimple extends CalcSlopeStrategy {

        @Override
        public double getSuggestSlope(int index, ChargingDatas chargingData) {
            List<ChargingData> chargingDatas = chargingData.getChargingDatas();
            if (index == 1) {
                ChargingData pre = chargingDatas.get(index - 1);
                ChargingData current = chargingDatas.get(index);
                int deltaTime = current.getTime() - pre.getTime();
                int deltaBattery = current.getBattery() - pre.getBattery();
                float battery_time = deltaBattery * 1f / deltaTime;
                return battery_time;
            } else {
                ChargingData pre = chargingDatas.get(index - 1);
                ChargingData prePre = chargingDatas.get(index - 2);
                ChargingData current = chargingDatas.get(index);

                int deltaTime = current.getTime() - pre.getTime();
                int deltaBattery = current.getBattery() - pre.getBattery();
                float battery_time = deltaBattery * 1f / deltaTime;

                int deltaTime1 = pre.getTime() - prePre.getTime();
                int deltaBattery1 = pre.getBattery() - prePre.getBattery();
                float battery_time1 = deltaBattery1 * 1f / deltaTime1;

                return (battery_time + battery_time1) / 2;
            }

        }
    }

    public static class Average extends CalcSlopeStrategy {

        @Override
        public double getSuggestSlope(int index, ChargingDatas chargingData) {
            List<ChargingData> chargingDatas = chargingData.getChargingDatas();
            int size = chargingDatas.size();
            List<Float> battery_times = new ArrayList<Float>(size - 1);
            for (int i = 1; i <= index; i++) {
                ChargingData pre = chargingDatas.get(i - 1);
                ChargingData current = chargingDatas.get(i);
                int deltaTime = current.getTime() - pre.getTime();
                int deltaBattery = current.getBattery() - pre.getBattery();
                float battery_time = deltaBattery * 1f / deltaTime;
                battery_times.add(battery_time);
            }
            float sum = 0;
            for (int i = 0; i < battery_times.size(); i++) {
                sum = sum + battery_times.get(i);
            }
            //预期的斜率
            float expectBatteryTimes = sum / battery_times.size();
            return expectBatteryTimes;
        }

    }

    /**
     *
     * 前90%用一次函数，
     * 后10%用前一个斜率和后一个斜率的比例算出当前的斜率
     *
     * @Description
     */
    public static class Exponential extends CalcSlopeStrategy {

        @Override
        public double getSuggestSlope(int index, ChargingDatas chargingData) {
            List<ChargingData> chargingDatas = chargingData.getChargingDatas();
            ChargingData current = chargingDatas.get(index);
            if (current.getBattery() < 0.9f * chargingData.getScaleBattery() || chargingDatas.size() <= 2) {
                ChargingData pre = chargingDatas.get(index - 1);
                int deltaTime = current.getTime() - pre.getTime();
                int deltaBattery = current.getBattery() - pre.getBattery();
                float slope = deltaBattery * 1f / deltaTime;
                return slope;
            } else {
                float y1 = current.getBattery();
                float x1 = current.getTime();
                ChargingData pre = chargingDatas.get(index - 1);
                float y2 = pre.getBattery();
                float x2 = pre.getTime();
                double currentSlope = (1f * y1 - y2) / (x1 - x2);
                double preSlope = pre.getSlope();
                double xSlope = 0;
                if (preSlope == 0 || currentSlope > preSlope) {
                    return currentSlope;
                } else {
                    xSlope = currentSlope * currentSlope / preSlope;
                }
                return xSlope;
            }
        }
    }
}
